package raft

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"sync"
	"time"
)

// Debugging
const Debug = 0

func DPrintf(format string, a ...interface{}) (n int, err error) {
	if Debug > 0 {
		log.Printf(format, a...)
	}
	return
}
// log info by with level
type LogLevel int
const(
	 LockL LogLevel =4
	 DebugL LogLevel= 3
	 ProductL LogLevel= 1
	 NullL LogLevel = 0
)
const CurLogLevel = NullL

//func (rf *Raft)Log(logLevel LogLevel,strs ...string){
//	if logLevel<=CurLogLevel{
//		rf.Fprint(strs...)
//	}
//}
func (rf *Raft)flushLog(){
	rf.logsyner.Lock()
	if len(rf.logInfo)!=0{
		rf.Fprint(rf.logInfo)
	}
	rf.logsyner.Unlock()

}
func (rf *Raft)Log(logLevel LogLevel,strs string){
	str := ""
	str = fmt.Sprintf("[LogTag:%s]\n%s\n",getCurTimeStamp(),strs)
	rf.logsyner.Lock()
	if logLevel<=CurLogLevel{
		rf.logInfo+=str
	}
	rf.logsyner.Unlock()
}
//var syner sync.Mutex
// log info in separate files
//func (rf *Raft)LogInitialize(logFd string){
//	syner.Lock()
//	syner.Unlock()
//	syner.log_file = logFd
//	file, err := os.OpenFile(logFd, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
//	if err != nil {
//		fmt.Println("OpenFile Err", err)
//		return
//	}
//	defer file.Close()
//}
//func (rf *Raft) Fprint(strs ...string) {
//	rf.logsyner.Lock()
//	defer rf.logsyner.Unlock()
//	file, err := os.OpenFile(rf.logFd, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
//	if err != nil {
//		fmt.Println("OpenFile Err", err)
//		return
//	}
//	defer file.Close()
//	str := ""
//	for i := 0; i < len(strs); i++ {
//		str += strs[i]
//	}
//	str = getCurTimeStamp()+"\n"+str+"\n"
//	_, err = file.WriteString(str)
//	if err != nil {
//		fmt.Println("WriteFile Err", err)
//		return
//	}
//}


func (rf *Raft) Fprint(str string) {
		//rf.logsyner.Lock()
		//defer rf.logsyner.Unlock()
		file, err := os.OpenFile(rf.logFd, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
		if err != nil {
			fmt.Println("OpenFile Err", err)
			return
		}
		defer file.Close()

		_, err = file.WriteString(str)
		if err != nil {
			fmt.Println("WriteFile Err", err)
			return
		}
	}

// lockedRand is a small wrapper around rand.Rand to provide
// synchronization among multiple raft groups. Only the methods needed
// by the code are exposed (e.g. Intn).
type lockedRand struct {
	mu   sync.Mutex
	rand *rand.Rand
}
func (r *lockedRand) Intn(n int) int {
	r.mu.Lock()
	v := r.rand.Intn(n)
	r.mu.Unlock()
	return v
}
var globalRand = &lockedRand{
	rand: rand.New(rand.NewSource(time.Now().UnixNano())),
}